package com.yt.base.service.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import com.yt.base.model.AclOperation;
import com.yt.base.model.AclUser;
import com.yt.base.service.AclCategoryService;
import com.yt.core.dao.PagingBean;
import com.yt.core.dao.filter.DynamicSQLFilterImpl;
import com.yt.core.dao.filter.QueryFilter;
import com.yt.core.service.GenericServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.yt.base.dao.AclGroupOperationDao;
import com.yt.base.dao.AclUserOperationDao;
import com.yt.base.model.AclGroupOperation;
import com.yt.base.model.AclUserOperation;
import com.yt.base.service.AclOperationService;
import com.yt.base.service.AclPrivilegeService;
import com.yt.base.service.AclUserOperationService;
import com.yt.base.vo.UserMenuVo;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class AclUserOperationServiceImpl extends GenericServiceImpl<AclUserOperation, Long> implements AclUserOperationService {
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	private AclUserOperationDao dao;
	
	@Autowired
	private AclGroupOperationDao groupOpDao;
	@Resource
	private AclCategoryService aclCategoryService;
	@Resource
	private AclPrivilegeService aclPrivilegeService;
	@Resource
	private AclOperationService aclOperationService;
	
	public AclUserOperationServiceImpl(AclUserOperationDao dao) {
		super(dao);
		this.dao = dao;
	}
	
	@Override
	public List<AclUserOperation> findByUser(Long userId) {
		QueryFilter filter = new DynamicSQLFilterImpl();
		filter.setPagingBean(new PagingBean(0, 5000));
		filter.addFilter("Q_userId_L_EQ", userId.toString());
		return dao.find(filter);
	}
	
	@Override
	public void removeUserOp(Long uid) {
		dao.removeByUser(uid);
	}
	
	@Override
	public void batchDelete(List<Long> idList) {
		if (!idList.isEmpty()) {
			int n = dao.batchDelete(idList);
			logger.debug("预计插入数量{}, 实际入库数量{}", idList.size(), n);
		}
	}
	
	@Override
	public void batchInsert(List<AclUserOperation> opList) {
		if (opList != null && !opList.isEmpty()) {
			int num = dao.batchInsert(opList);
			logger.debug("预期入库数量{}, 实际入库数量{}", opList.size(), num);
		}
	}
	
	@Override
	public void modify(AclUser user, List<String> aclList) {
		
		long uid = user.getId();
		
		Splitter splitter = Splitter.on('_').trimResults();
		List<AclUserOperation> userOpList = findByUser(uid);
		if (userOpList == null || userOpList.isEmpty()) {
			// 直接保存
			List<AclUserOperation> opList = Lists.newArrayList();
			for (String acl : aclList) {
				List<String> segList = splitter.splitToList(acl);
				if (segList.size() == 3) {
					AclUserOperation op = new AclUserOperation(uid, Long.valueOf(segList.get(0)), Long.valueOf(segList.get(1)), Long.valueOf(segList.get(2)));
					opList.add(op);
				}
			}
			batchInsert(opList);
		} else {
			// Merge
			List<AclUserOperation> dbOpList = userOpList;
			Map<String, Long> dbOpMap = Maps.newHashMap();
			for (AclUserOperation op : dbOpList) {
				StringBuilder sb = Joiner.on('_').appendTo(new StringBuilder(), new Long[] { op.getCategoryId(), op.getPrivilegeId(), op.getOperationId() });
				dbOpMap.put(sb.toString(), op.getId());
			}
			
			List<AclUserOperation> insertList = Lists.newArrayList();
			List<Long> removeList = Lists.newArrayList();
			for (String acl : aclList) {
				if (dbOpMap.containsKey(acl)) {
					dbOpMap.remove(acl);
				} else {
					List<String> segList = splitter.splitToList(acl);
					if (segList.size() == 3) {
						AclUserOperation op = new AclUserOperation(uid, Long.valueOf(segList.get(0)), Long.valueOf(segList.get(1)), Long.valueOf(segList.get(2)));
						insertList.add(op);
					}
				}
			}
			removeList.addAll(dbOpMap.values());
			
			batchInsert(insertList);
			batchDelete(removeList);
		}
		
	}
	
	@Override
	public List<String> getUserKeys(AclUser user) {
		List<String> keyList = Lists.newArrayList();
		List<AclUserOperation> userOpList = findByUser(user.getId());
		//组权限
		if (userOpList != null && !userOpList.isEmpty()) {
			for (AclUserOperation op : userOpList) {
				StringBuilder sb = new StringBuilder().append(op.getCategoryId()).append("_").append(op.getPrivilegeId()).append("_").append(op.getOperationId());
				keyList.add(sb.toString());
			}
		}
		//单个权限
		List<AclGroupOperation> groupOpList = groupOpDao.findByGroup(user.getGroupId());
		if (groupOpList != null && groupOpList.size() > 0) {
			for (AclGroupOperation op : groupOpList) {
				StringBuilder sb = new StringBuilder().append(op.getCategoryId()).append("_").append(op.getPrivilegeId()).append("_").append(op.getOperationId());
				keyList.add(sb.toString());
			}
		}
		
		return keyList;
	}
	
	public UserMenuVo getUserMenu(AclUser user) {
		List<String> keys = getUserKeys(user);
		UserMenuVo menuVo = new UserMenuVo();
		Set<String> tmpSet = new HashSet<String>();
		String[] tmpKeys = null;
		String tmpKey = null;
		Long catId = 0l;
		Long priId = 0l;
		Long opId = 0l;
		AclOperation aclOperation = null;
		for (String key : keys) {
			tmpKeys = StringUtils.split(key, "_");
			catId = NumberUtils.toLong(tmpKeys[0]);
			priId = NumberUtils.toLong(tmpKeys[1]);
			opId = NumberUtils.toLong(tmpKeys[2]);
			tmpKey = catId + "";
			
			if (!tmpSet.contains(tmpKey)) {
				menuVo.addCategory(aclCategoryService.get(catId));
				tmpSet.add(tmpKey);
			}
			
			tmpKey = catId + "_" + priId;
			if (!tmpSet.contains(tmpKey)) {
				menuVo.addPrividege(aclPrivilegeService.get(priId));
				tmpSet.add(tmpKey);
			}
			tmpKey += "_" + opId;
			if (!tmpSet.contains(tmpKey)) {
				aclOperation = aclOperationService.get(opId);
				menuVo.addOperation(aclOperation);
				if (aclOperation != null)
					menuVo.putOperationKeys(catId + "_" + priId + "_" + aclOperation.getKey());
				tmpSet.add(tmpKey);
			}
			aclOperation = null;
		}
		
		return menuVo;
	}
}
